package com.hgyc.mom.mes.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hgyc.mom.common.constant.CacheConstants;
import com.hgyc.mom.common.redis.RedisCache;
import com.hgyc.mom.common.util.DateUtils;
import com.hgyc.mom.mes.entity.MesStationCollect;
import com.hgyc.mom.mes.entity.MesStationCollectDetail;
import com.hgyc.mom.mes.enums.ScanResultEnum;
import com.hgyc.mom.mes.event.ProductChangeEvent;
import com.hgyc.mom.mes.mapper.MesStationCollectMapper;
import com.hgyc.mom.mes.service.MesStationCollectDetailService;
import com.hgyc.mom.mes.service.MesStationCollectService;
import com.hgyc.mom.mes.vo.CollectScanVO;
import com.hgyc.mom.mes.vo.LineInProductVO;
import com.hgyc.mom.mes.vo.MesStationCollectVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 产品SN过站采集记录Service业务层实现
 *
 * @author fwj
 * @since 2025-07-04
 */
@Slf4j
@Service
public class MesStationCollectServiceImpl extends ServiceImpl<MesStationCollectMapper, MesStationCollect> implements MesStationCollectService {

    @Autowired
    private MesStationCollectDetailService mesStationCollectDetailService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ApplicationEventPublisher publisher;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveCollect(MesStationCollectVO mesStationCollectVO) {
        // TODO 其他逻辑
        save(mesStationCollectVO);

        //新增过站采集明细
        List<MesStationCollectDetail> details = mesStationCollectVO.getAddDetails();
        if (!CollectionUtils.isEmpty(details)) {
            details.forEach(item -> {
                item.setId(null);
                item.setCollectId(mesStationCollectVO.getId());
            });
            mesStationCollectDetailService.saveBatch(details);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCollect(MesStationCollectVO mesStationCollectVO) {
        // TODO 其他逻辑
        updateById(mesStationCollectVO);

        //删除过站采集明细
        if (!CollectionUtils.isEmpty(mesStationCollectVO.getDeleteDetailIds())) {
            mesStationCollectDetailService.removeBatchByIds(mesStationCollectVO.getDeleteDetailIds());
        }

        //新增过站采集明细
        List<MesStationCollectDetail> details = mesStationCollectVO.getAddDetails();
        if (!CollectionUtils.isEmpty(details)) {
            details.forEach(item -> {
                item.setId(null);
                item.setCollectId(mesStationCollectVO.getId());
            });
            mesStationCollectDetailService.saveBatch(details);
        }

        //更新过站采集明细
        if (!CollectionUtils.isEmpty(mesStationCollectVO.getUpdateDetails())) {
            List<MesStationCollectDetail> updateDetails = mesStationCollectVO.getUpdateDetails();
            mesStationCollectDetailService.updateBatchById(updateDetails);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeCollect(List<Long> ids) {
        // TODO 其他逻辑
        removeByIds(ids);
        //删除过站采集明细
        mesStationCollectDetailService.deleteBatchByParentIds(ids);
    }

    @Override
    public CollectScanVO scan(CollectScanVO collectScanVO) {
        Long currentUserId = Long.parseLong((String) StpUtil.getLoginId());

        collectScanVO.setResult("OK");
        collectScanVO.setResultCode(ScanResultEnum.SUCCESS.getCode());

        //把当前产线生产中的产品放入缓存
        if (collectScanVO.getLineId() != null && collectScanVO.getMaterialId() != null) {
            LineInProductVO lineInProductVO = new LineInProductVO();
            lineInProductVO.setLineId(collectScanVO.getLineId());
            lineInProductVO.setMaterialId(collectScanVO.getMaterialId());
            lineInProductVO.setCreateBy(currentUserId);

            //判断是否转产
            boolean changeProduct = false;

            LineInProductVO processProduct = redisCache.getCacheObject(CacheConstants.LINE_IN_PRODUCT_DATA_CACHE + collectScanVO.getLineId(), LineInProductVO.class);
            if (processProduct != null) {
                if (!Objects.equals(collectScanVO.getMaterialId(), processProduct.getMaterialId())) {
                    changeProduct = true;
                }
            } else {
                changeProduct = true;
            }

            if (changeProduct) {
                //提交事件
                publisher.publishEvent(new ProductChangeEvent(lineInProductVO));

                redisCache.setCacheObject(CacheConstants.LINE_IN_PRODUCT_DATA_CACHE + collectScanVO.getLineId(), lineInProductVO);
            }
        }

        //1. TODO 先判断条码是否存在

        //2. TODO 判断扫描的铭牌和当前生产物料一致

        //3.查询是否已经扫描过该条码
        boolean exists = existsByCode(collectScanVO.getSn());
        if (exists) {
            collectScanVO.setResult("NG");
            collectScanVO.setMsg(String.format("[%s]条码已扫描，请勿重复扫描", collectScanVO.getSn()));
            collectScanVO.setResultCode(ScanResultEnum.BARCODE_DUPLICATE.getCode());
            return collectScanVO;
        }

        // 3. 累加已完成数量
        collectScanVO.setCompletedNum(Optional.ofNullable(collectScanVO.getCompletedNum())
                .orElse(BigDecimal.ZERO).add(BigDecimal.ONE));

        // 4. 添加扫描记录
        MesStationCollect stationCollect = new MesStationCollect();
        stationCollect.setMaterialId(collectScanVO.getMaterialId());
        stationCollect.setSn(collectScanVO.getSn());
        stationCollect.setStationId(collectScanVO.getLineId());
        stationCollect.setLineId(collectScanVO.getLineId());
        stationCollect.setWorkshopId(collectScanVO.getWorkshopId());
        stationCollect.setOperator(currentUserId);
        stationCollect.setCollectTime(LocalDateTime.now());
        stationCollect.setResult(collectScanVO.getResult());
        this.save(stationCollect);

        collectScanVO.setCollectId(stationCollect.getId());
        return collectScanVO;
    }

    private boolean existsByCode(String code) {
        LambdaQueryWrapper<MesStationCollect> qw = new LambdaQueryWrapper<>();
        qw.eq(MesStationCollect::getSn, code);
        return baseMapper.selectCount(qw) > 0;
    }
}